fn create_box() {
    let _box1 = Box::new(3i32);
    // `_box1` 在这里被销毁，内存得到释放
}

// 因为变量要负责释放它们拥有的资源，所以资源只能拥有一个所有者。这也防止了资源的重复释放。注意并非所有变量都拥有资源（例如引用）。

// 在进行赋值（let x = y）或通过值来传递函数参数（foo(x)）的时候，资源的所有权（ownership）会发生转移。按照 Rust 的说法，这被称为资源的移动（move）。

// 在移动资源之后，原来的所有者不能再被使用，这可避免悬挂指针（dangling pointer）的产生。
// 此函数取得堆分配的内存的所有权
fn destroy_box(c: Box<i32>) {
    println!("Destroying a box that contains {}", c);

    // `c` 被销毁且内存得到释放
}

fn main() {
     // 在堆上分配一个整型数据
    let _box2 = Box::new(5i32);
    // 嵌套作用域：
    {
        // 在堆上分配一个整型数据
        let _box3 = Box::new(4i32);
        // `_box3` 在这里被销毁，内存得到释放
    }
     // 创建一大堆 box（只是因为好玩）。
    // 完全不需要手动释放内存！
    for _ in 0u32..1_000 {
        create_box();
    }
     // `_box2` 在这里被销毁，内存得到释放

     let _x = ToDrop;
     println!("Made a ToDrop!");


     // 栈分配的整型
    let x = 5u32;

    // 将 `x` *复制*到 `y`——不存在资源移动
    let y = x;

    // 两个值各自都可以使用
    println!("x is {}, and y is {}", x, y);

    // `a` 是一个指向堆分配的整数的指针
    let a = Box::new(5i32);

    println!("a contains: {}", a);

    // *移动* `a` 到 `b`
    let b = a;
    // 把 `a` 的指针地址（而非数据）复制到 `b`。现在两者都指向
    // 同一个堆分配的数据，但是现在是 `b` 拥有它。

    // 报错！`a` 不能访问数据，因为它不再拥有那部分堆上的内存。
    //println!("a contains: {}", a);
    // 试一试 ^ 去掉此行注释

    // 此函数从 `b` 中取得堆分配的内存的所有权
    destroy_box(b);

    // 此时堆内存已经被释放，这个操作会导致解引用已释放的内存，而这是编译器禁止的。
    // 报错！和前面出错的原因一样。
    //println!("b contains: {}", b);
    // 试一试 ^ 去掉此行注释

    // 当所有权转移时，数据的可变性可能发生改变。
    let immutable_box = Box::new(5u32);

    println!("immutable_box contains {}", immutable_box);

    // 可变性错误
    //*immutable_box = 4;

    // *移动* box，改变所有权（和可变性）
    let mut mutable_box = immutable_box;

    println!("mutable_box contains {}", mutable_box);

    // 修改 box 的内容
    *mutable_box = 4;

    println!("mutable_box now contains {}", mutable_box);

    // 多数情况下，我们更希望能访问数据，同时不取得其所有权。为实现这点，Rust 使用了借用（borrowing）机制。对象可以通过引用（&T）来传递，从而取代通过值（T）来传递。
    // 编译器（通过借用检查）静态地保证了引用总是指向有效的对象。也就是说，当存在引用指向一个对象时，该对象不能被销毁。

    // 此函数取得一个 box 的所有权并销毁它
    fn eat_box_i32(boxed_i32: Box<i32>) {
        println!("Destroying box that contains {}", boxed_i32);
    }

    // 此函数借用了一个 i32 类型
    fn borrow_i32(borrowed_i32: &i32) {
        println!("This int is: {}", borrowed_i32);
    }

    // / 创建一个装箱的 i32 类型，以及一个存在栈中的 i32 类型。
    let boxed_i32 = Box::new(5_i32);
    let stacked_i32 = 6_i32;

    // 借用了 box 的内容，但没有取得所有权，所以 box 的内容之后可以再次借用。
    // 译注：请注意函数自身就是一个作用域，因此下面两个函数运行完成以后，
    // 在函数中临时创建的引用也就不复存在了。
    borrow_i32(&boxed_i32);
    borrow_i32(&stacked_i32);

    {
        // 取得一个对 box 中数据的引用
        let _ref_to_i32: &i32 = &boxed_i32;

        // 报错！
        // 当 `boxed_i32` 里面的值被借用时，不能销毁 `boxed_i32`。
        // eat_box_i32(boxed_i32);
        // 改正 ^ 注释掉此行

        // `_ref_to_i32` 离开作用域且不再被借用。
    }

    // `boxed_i32` 现在可以将所有权交给 `eat_box_i32` 并被销毁。
    //（译注：能够销毁是因为已经不存在对 `boxed_i32` 的引用）
    eat_box_i32(boxed_i32);

    // 可变数据可以使用 &mut T 进行可变借用。这叫做可变引用（mutable reference），
    // 它使借用者可以读/写数据。相反，&T 通过不可变引用（immutable reference）来借用数据，借用者可以读数据而不能更改数据：

    #[allow(dead_code)]
    #[derive(Clone, Copy)]
    struct Book {
        // `&'static str` 是一个对分配在只读内存区的字符串的引用
        author: &'static str,
        title: &'static str,
        year: u32,
    }

    // 此函数接受一个对 Book 类型的引用
    fn borrow_book(book: &Book) {
        println!("I immutably borrowed {} - {} edition", book.title, book.year);
    }

    // 此函数接受一个对可变的 Book 类型的引用，它把年份 `year` 改为 2014 年
    fn new_edition(book: &mut Book) {
        book.year = 2014;
        println!("I mutably borrowed {} - {} edition", book.title, book.year);
    }


     // 创建一个名为 `immutabook` 的不可变的 Book 实例
     let immutabook = Book {
        // 字符串字面量拥有 `&'static str` 类型
        author: "Douglas Hofstadter",
        title: "Gödel, Escher, Bach",
        year: 1979,
    };

    // 创建一个 `immutabook` 的可变拷贝，命名为 `mutabook`
    let mut mutabook = immutabook;

    // 不可变地借用一个不可变对象
    borrow_book(&immutabook);

    // 不可变地借用一个可变对象
    borrow_book(&mutabook);

    // 可变地借用一个可变对象
    new_edition(&mut mutabook);

    // 报错！不能可变地借用一个不可变对象
    // new_edition(&mut immutabook);
    // 改正 ^ 注释掉此行

    // 当数据被不可变地借用时，它还会冻结（freeze）。已冻结的数据无法通过原始对象来修改，直到对这些数据的所有引用离开作用域为止。

    let mut _mutable_integer = 7i32;

    {
        // 借用 `_mutable_integer`
        let large_integer = &_mutable_integer;

        // 报错！`_mutable_integer` 在本作用域被冻结
        // _mutable_integer = 50;
        // 改正 ^ 注释掉此行
        println!("Immutably borrowed {}", large_integer);

        // `_large_integer` 离开作用域
    }

    // 正常运行！`_mutable_integer` 在这作用域没有冻结
    _mutable_integer = 3;

    // 数据可以进行多次不可变借用，但是在不可变借用的期间，原始数据不可进行可变借用。
    // 另一方面，在同一时刻内只允许有一个可变借用。只有在可变引用离开作用域之后，原始数据才可再次被借用。
    #[derive(Clone, Debug, Copy)]
    struct Point { x: i32, y: i32, z: i32 }

    let mut point = Point { x: 0, y: 0, z: 0 };

    {
        let borrowed_point = &point;
        let another_borrow = &point;

        // 通过引用和原始所有者来访问数据
        println!("Point has coordinates: ({}, {}, {})",
                 borrowed_point.x, another_borrow.y, point.z);

        // 报错！不能可变地借用 `point` ，因为现在它有不可变的借用。
        //let mutable_borrow = &mut point;
        // 试一试 ^ 取消此行注释。

        // 不可变引用离开作用域
    }

    {
        let mutable_borrow = &mut point;

        // 通过可变引用来改变数据
        mutable_borrow.x = 5;
        mutable_borrow.y = 2;
        mutable_borrow.z = 1;

        // 报错！不能不可变地借用 `point`，因为现在它有可变的借用。
        //let y = &point.y;
        // 试一试 ^ 取消此行注释。

        // 报错！不能打印，因为 `println!` 会创建一个不可变引用。
        //println!("Point Z coordinate is {}", point.z);
        // 试一试 ^ 取消此行注释。

        // 可以工作！可变引用可以作为不可变的传给 `println!`。
        println!("Point has coordinates: ({}, {}, {})",
                 mutable_borrow.x, mutable_borrow.y, mutable_borrow.z);

        // 可变引用离开作用域
    }

    // 现在又可以不可变地借用 `point` 了。
    let borrowed_point = &point;
    println!("Point now has coordinates: ({}, {}, {})",
             borrowed_point.x, borrowed_point.y, borrowed_point.z);


    #[derive(Clone, Copy)]
    struct Point1 { x: i32, y: i32 }
    let c = 'Q';

    // 赋值语句中左边的 `ref` 关键字等价于右边的 `&` 符号。
    let ref ref_c1 = c;
    let ref_c2 = &c;

    println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);

    let point = Point1 { x: 0, y: 0 };

    // 在解构一个结构体时 `ref` 同样有效。
    let _copy_of_x = {
        // `ref_to_x` 是一个指向 `point` 的 `x` 字段的引用。
        let Point1 { x: ref ref_to_x, y: _ } = point;

        // 返回一个 `point` 的 `x` 字段的拷贝。
        *ref_to_x
    };

    // `point` 的可变拷贝
    let mut mutable_point = point;

    {
        // `ref` 可以与 `mut` 结合以创建可变引用。
        let Point1 { x: _, y: ref mut mut_ref_to_y } = mutable_point;

        // 通过可变引用来改变 `mutable_point` 的字段 `y`。
        *mut_ref_to_y = 1;
    }

    println!("point is ({}, {})", point.x, point.y);
    println!("mutable_point is ({}, {})", mutable_point.x, mutable_point.y);

    // 包含一个指针的可变元组
    let mut mutable_tuple = (Box::new(5u32), 3u32);

    {
        // 解构 `mutable_tuple` 来改变 `last` 的值。
        let (_, ref mut last) = mutable_tuple;
        *last = 2u32;
    }

    println!("tuple is {:?}", mutable_tuple);


    // 生命周期（lifetime）是这样一种概念，编译器（中的借用检查器）用它来保证所有的借用都是有效的。
    // 确切地说，一个变量的生命周期在它创建的时候开始，在它销毁的时候结束。
    // 虽然生命周期和作用域经常被一起提到，但它们并不相同。

    // 例如考虑这种情况，我们通过 & 来借用一个变量。
    // 该借用拥有一个生命周期，此生命周期由它声明的位置决定。
    // 于是，只要该借用在出借者（lender）被销毁前结束，借用就是有效的。然而，借用的作用域则是由使用引用的位置决定的。

    // 下面使用连线来标注各个变量的创建和销毁，从而显示出生命周期。
    // `i` 的生命周期最长，因为它的作用域完全覆盖了 `borrow1` 和
    // `borrow2` 的。`borrow1` 和 `borrow2` 的周期没有关联，
    // 因为它们各不相交。

    {
        let i = 3; // Lifetime for `i` starts. ────────────────┐
        //                                                           │
        { //                                                         │
            let borrow1 = &i; // `borrow1` lifetime starts. ──┐│
            //                                                      ││
            println!("borrow1: {}", borrow1); //                    ││
        } // `borrow1 ends. ──────────────────────────────────-----┘│
        //                                                           │
        //                                                           │
        { //                                                         │
            let borrow2 = &i; // `borrow2` lifetime starts. ──┐│
            //                                                      ││
            println!("borrow2: {}", borrow2); //                    ││
        } // `borrow2` ends. ─────────────────────────────────-----┘│
        //                                                           │
    }//   Lifetime ends. ─────────────────────────────────────------┘

    // 借用检查器使用显式的生命周期标记来明确引用的有效时间应该持续多久。
    // 在生命周期没有省略[^1]的情况下，Rust 需要显式标注来确定引用的生命周期应该是什么样的。
    // 可以用撇号显式地标出生命周期，语法如下：

    // foo<'a>
    // `foo` 带有一个生命周期参数 `'a`

    // 和闭包类似，使用生命周期需要泛型。另外这个生命周期的语法也表明了 foo 的生命周期不能超出 'a 的周期。若要给类型显式地标注生命周期，其语法会像是 &'a T 这样，其中 'a 的作用刚刚已经介绍了

    //     foo<'a, 'b>
    // // `foo` 带有生命周期参数 `'a` 和 `'b` foo 的生命周期不能超出 'a 和 'b 中任一个的周期。


    // `print_refs` 接受两个 `i32` 的引用，它们有不同的生命周期 `'a` 和 `'b`。
    // 这两个生命周期都必须至少要和 `print_refs` 函数一样长。
    fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
        println!("x is {} and y is {}", x, y);
    }

    // 不带参数的函数，不过有一个生命周期参数 `'a`。
    fn failed_borrow<'a>() {
        let _x = 12;

        // 报错：`_x` 的生命周期不够长
        //let y: &'a i32 = &_x;
        // 在函数内部使用生命周期 `'a` 作为显式类型标注将导致失败，因为 `&_x` 的
        // 生命周期比 `y` 的短。短生命周期不能强制转换成长生命周期。
    }


     // 创建变量，稍后用于借用。
     let (four, nine) = (4, 9);

     // 两个变量的借用（`&`）都传进函数。
     print_refs(&four, &nine);
     // 任何被借用的输入量都必须比借用者生存得更长。
     // 也就是说，`four` 和 `nine` 的生命周期都必须比 `print_refs` 的长。
 
     failed_borrow();
     // `failed_borrow` 未包含引用，因此不要求 `'a` 长于函数的生命周期，
     // 但 `'a` 寿命确实更长。因为该生命周期从未被约束，所以默认为 `'static`。

    //  排除省略（elision）的情况，带上生命周期的函数签名有一些限制：

    //  任何引用都必须拥有标注好的生命周期。
    //  任何被返回的引用都必须有和某个输入量相同的生命周期或是静态类型（static）。

    // 另外要注意，如果没有输入的函数返回引用，有时会导致返回的引用指向无效数据，
    // 这种情况下禁止它返回这样的引用。下面例子展示了一些合法的带有生命周期的函数：

    // 一个拥有生命周期 `'a` 的输入引用，其中 `'a` 的存活时间
    // 至少与函数的一样长。
    fn print_one<'a>(x: &'a i32) {
        println!("`print_one`: x is {}", x);
    }

    // 可变引用同样也可能拥有生命周期。
    fn add_one<'a>(x: &'a mut i32) {
        *x += 1;
    }

    // 拥有不同生命周期的多个元素。对下面这种情形，两者即使拥有
    // 相同的生命周期 `'a` 也没问题，但对一些更复杂的情形，可能
    // 就需要不同的生命周期了。
    fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {
        println!("`print_multi`: x is {}, y is {}", x, y);
    }

    // 返回传递进来的引用也是可行的。
    // 但必须返回正确的生命周期。
    fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x }

    //fn invalid_output<'a>() -> &'a i32 { &7 }
    // 上面代码是无效的：`'a` 存活的时间必须比函数的长。
    // 这里的 `&7` 将会创建一个 `i32` 类型，然后对它取引用。
    // 数据在离开作用域时删掉，返回一个指向无效数据的引用。

    let x = 7;
    let y = 9;

    print_one(&x);
    print_multi(&x, &y);

    let z = pass_x(&x, &y);
    print_one(z);

    let mut t = 3;
    add_one(&mut t);
    print_one(&t);


    struct Owner(i32);

    impl Owner {
        // 标注生命周期，就像独立的函数一样。
        fn add_one<'a>(&'a mut self) { self.0 += 1; }
        fn print<'a>(&'a self) {
            println!("`print`: {}", self.0);
        }
    }
    // 方法一般是不需要标明生命周期的，因为 self 的生命周期会赋给所有的输出 生命周期参数

    let mut owner  = Owner(18);

    owner.add_one();
    owner.print();


    // 一个 `Borrowed` 类型，含有一个指向 `i32` 类型的引用。
    // 该引用必须比 `Borrowed` 寿命更长。
    #[derive(Debug)]
    struct Borrowed<'a>(&'a i32);

    // 和前面类似，这里的两个引用都必须比这个结构体长寿。
    #[derive(Debug)]
    struct NamedBorrowed<'a> {
        x: &'a i32,
        y: &'a i32,
    }

    // 一个枚举类型，其取值不是 `i32` 类型就是一个指向 `i32` 的引用。
    #[derive(Debug)]
    enum Either<'a> {
        Num(i32),
        Ref(&'a i32),
    }

    let x = 18;
    let y = 15;

    let single = Borrowed(&x);
    let double = NamedBorrowed { x: &x, y: &y };
    let reference = Either::Ref(&x);
    let number    = Either::Num(y);

    println!("x is borrowed in {:?}", single);
    println!("x and y are borrowed in {:?}", double);
    println!("x is borrowed in {:?}", reference);
    println!("y is *not* borrowed in {:?}", number);


    // trait 方法中生命期的标注基本上与函数类似。注意，impl 也可能有生命周期的标注。

    // 带有生命周期标注的结构体。
    #[derive(Debug)]
    struct Borrowed2<'a> {
        x: &'a i32,
    }

    // 给 impl 标注生命周期。
    impl<'a> Default for Borrowed2<'a> {
        fn default() -> Self {
            Self {
                x: &10,
            }
        }
    }

    let b: Borrowed2 = Default::default();
    println!("b is {:?}", b);

//     就如泛型类型能够被约束一样，生命周期（它们本身就是泛型）也可以使用约束。: 字符的意义在这里稍微有些不同，不过 + 是相同的。注意下面的说明：

// T: 'a：在 T 中的所有引用都必须比生命周期 'a 活得更长。
// T: Trait + 'a：T 类型必须实现 Trait trait，并且在 T 中的所有引用都必须比 'a 活得更长。

    use std::fmt::Debug; // 用于约束的 trait。

    #[derive(Debug)]
    struct Ref<'a, T: 'a>(&'a T);
    // `Ref` 包含一个指向指向泛型类型 `T` 的引用，其中 `T` 拥有一个未知的生命周期
    // `'a`。`T` 拥有生命周期限制， `T` 中的任何*引用*都必须比 `'a` 活得更长。另外
    // `Ref` 的生命周期也不能超出 `'a`。

    // 一个泛型函数，使用 `Debug` trait 来打印内容。
    fn print<T>(t: T) where
        T: Debug {
        println!("`print`: t is {:?}", t);
    }

    // 这里接受一个指向 `T` 的引用，其中 `T` 实现了 `Debug` trait，并且在 `T` 中的
    // 所有*引用*都必须比 `'a'` 存活时间更长。另外，`'a` 也要比函数活得更长。
    fn print_ref<'a, T>(t: &'a T) where
        T: Debug + 'a {
        println!("`print_ref`: t is {:?}", t);
    }
    let x = 7;
    let ref_x = Ref(&x);

    print_ref(&ref_x);
    print(ref_x);

    // 在这里，Rust 推导了一个尽可能短的生命周期。
    // 然后这两个引用都被强制转成这个生命周期。
    fn multiply<'a>(first: &'a i32, second: &'a i32) -> i32 {
        first * second
    }

    // `<'a: 'b, 'b>` 读作生命周期 `'a` 至少和 `'b` 一样长。
    // 在这里我们我们接受了一个 `&'a i32` 类型并返回一个 `&'b i32` 类型，这是
    // 强制转换得到的结果。
    fn choose_first<'a: 'b, 'b>(first: &'a i32, _: &'b i32) -> &'b i32 {
        first
    }

    let first = 2; // 较长的生命周期

    {
        let second = 3; // 较短的生命周期

        println!("The product is {}", multiply(&first, &second));
        println!("{} is the first", choose_first(&first, &second));
    };


//     static
// 'static 生命周期是可能的生命周期中最长的，它会在整个程序运行的时期中存在。'static 生命周期也可被强制转换成一个更短的生命周期。有两种方式使变量拥有 'static 生命周期，它们都把数据保存在可执行文件的只读内存区：

// 使用 static 声明来产生常量（constant）。
// 产生一个拥有 &'static str 类型的 string 字面量。

    // 产生一个拥有 `'static` 生命周期的常量。
    static NUM: i32 = 18;

    // 返回一个指向 `NUM` 的引用，该引用不取 `NUM` 的 `'static` 生命周期，
    // 而是被强制转换成和输入参数的一样。
    fn coerce_static<'a>(_: &'a i32) -> &'a i32 {
        &NUM
    }


    {
        // 产生一个 `string` 字面量并打印它：
        let static_string = "I'm in read-only memory";
        println!("static_string: {}", static_string);

        // 当 `static_string` 离开作用域时，该引用不能再使用，不过
        // 数据仍然存在于二进制文件里面。
    }

    {
        // 产生一个整型给 `coerce_static` 使用：
        let lifetime_num = 9;

        // 将对 `NUM` 的引用强制转换成 `lifetime_num` 的生命周期：
        let coerced_static = coerce_static(&lifetime_num);

        println!("coerced_static: {}", coerced_static);
    }

    println!("NUM: {} stays accessible!", NUM);

    fn elided_input(x: &i32) {
        println!("`elided_input`: {}", x)
    }
    
    fn annotated_input<'a>(x: &'a i32) {
        println!("`annotated_input`: {}", x)
    }

    // 类似地，`elided_pass` 和 `annotated_pass` 也拥有相同的签名，
    // 生命周期会被隐式地添加进 `elided_pass`：
    fn elided_pass(x: &i32) -> &i32 { x }

    fn annotated_pass<'a>(x: &'a i32) -> &'a i32 { x }
    let x = 3;

    elided_input(&x);
    annotated_input(&x);

    println!("`elided_pass`: {}", elided_pass(&x));
    println!("`annotated_pass`: {}", annotated_pass(&x));




}


// 作用域在所有权（ownership）、借用（borrow）和生命周期（lifetime）中起着重要作用。也就是说，作用域告诉编译器什么时候借用是合法的、什么时候资源可以释放、以及变量何时被创建或销毁。
// Rust 的变量不只是在栈中保存数据：它们也占有资源，比如 Box<T> 占有堆（heap）中的内存。Rust 强制实行 RAII（Resource Acquisition Is Initiallization，资源获取即初始化），所以任何对象在离开作用域时，它的析构 函数（destructor）就被调用，然后它占有的资源就被释放。

// 这种行为避免了资源泄漏（resource leak），所以你再也不用手动释放内存或者担心内存泄漏（memory leak）！下面是个快速入门示例。

// Rust 中的析构函数概念是通过 Drop trait 提供的。当资源离开作用域，就调用析构函数。你无需为每种类型都实现 Drop trait，只要为那些需要自己的析构函数逻辑的类型实现就可以了。

// 运行下列例子，看看 Drop trait 是怎样工作的。当 main 函数中的变量离开作用域，自定义的析构函数就会被调用：\\\

struct ToDrop;

impl Drop for ToDrop {
    fn drop(&mut self) {
        println!("ToDrop is being dropped");
    }
}

// 悬垂指针(Dangling pointers): 指向无效数据的指针（当我们了解数据在内存中如何存储之后，这个就很有意义）。
// 重复释放(Double frees): 试图对同一块内存地址释放两次，这会导致“未定义行为”。

// ```c++ std::string s = "have a nice day";```

// 初始化的字符串通常是在内存中使用堆和栈进行表示的，像下面这样：

//                     buffer
//                    /   capacity
//                  /   /    length
//                /   /    /
//             +–––+––––+––––+
// stack frame │ • │ 16 │ 15 │ <– s
//             +–│–+––––+––––+
//               │
//             [–│––––––––––––––––––––––––– capacity ––––––––––––––––––––––––––]
//               │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
//        heap │ H │ a │ v │ e │   │ a │   │ n │ i │ c │ e │   │ d │ a │ y │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

//             [––––––––––––––––––––––––– length ––––––––––––––––––––––––––]

// 理解存储在栈上的是std::string对象本身，这个对象的长度为三个字(word)，长度固定。它里面的字段包括指向一块分配在堆上的缓冲区(buffer)，也是实际存放数据的位置，还包括缓冲区容量以及文本长度。换句话说，std::string拥有它的缓冲区。当程序销毁这个字符串的时候，对应的缓冲区也会通过字符串的析构器被释放。
// 如果创建一个指向相同缓冲区中某个字符的指针，当字符串已经被销毁之后，指针指向的内容就是无效的，这时候我们就有一个悬垂指针，这是完全有可能的。


// 哪些数据存放在栈上，哪些数据存放在堆上，这取决于我们要处理的数据。在Rust里，任何固定大小(在编译期可以知道的大小)，
// 比如机器整数(machine integers)，浮点数类型，指针类型和一些其他类型会被存储在栈上。
// 动态的和“不确定大小(unsized)”数据被存储在堆上。这是因为这些不知道大小的类型，会经常地要么需要能够动态增长，
// 要么需要在被析构时执行准确地清理工作（这不仅仅是从栈上弹出一个值）。

// 这也是为什么在之前的例子里，拥有固定大小（一个缓冲区指针，容量和长度）的字符串对象本身是一个存储在栈上的指针，
// 而缓冲区（原始数据）存储在堆上。

// 在Rust里，每一个值都有一个决定其生命周期的唯一的所有者(owner)。
// let s = "Have a nice day".to_string();\
// 当某些值的所有者被“释放(freed)”，或者用Rust的术语“丢弃(dropped)”
// ，那么这个被拥有的值也会被丢弃。这些值在什么时候被丢弃？这才是吸引人的地方。
// 当这个程序离开了变量被生命的块(block)，这个变量就会被丢弃，变量的值也会被丢弃。

// 一个块可以是一个函数，一个if语句，或者几乎是任何用大括号引入的代码块。假定我们有下面的函数：

fn _greeting() {
    let s = "Have a nice day".to_string();
    println!("{}", s); // `s` is dropped here
}

// 只看上面的代码，我们就可以知道s的生命周期，
// 因为我们知道Rust会在执行到函数块末尾的时候丢弃它的值。当我们处理更复杂的数据结构时这也同样适用。让我们俩看看下面的代码：

// ```let names = vec!["Pascal".to_string(), "Christoph".to_string()];```
// 上面的代码创建了一个名字的vector。
// Rust的vector类似一个数组(array)或者列表(list)，但是它是动态增长的。
// 我们可以在运行时调用push()把值放进去。我们的内存看起来下面这样：

//             [–– names ––]
//             +–––+–––+–––+
// stack frame │ • │ 3 │ 2 │
//             +–│–+–––+–––+
//               │
//             [–│–– 0 –––] [–––– 1 ––––]
//             +–V–+–––+–––+–––+––––+–––+–––+–––+
//        heap │ • │ 8 │ 6 │ • │ 12 │ 9 │       │
//             +–│–+–––+–––+–│–+––––+–––+–––+–––+
//               │\   \   \  │
//               │ \   \    length
//               │  \    capacity
//               │    buffer │
//               │           │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+
//             │ P │ a │ s │ c │ a │ l │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+
//                           │
//                           │
//                         +–V–+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
//                         │ C │ h │ r │ i │ s │ t │ o │ p │ h │   │   │   │
//                         +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

// vector对象本身以及其容量和长度，类似于前面的字符串对象，是如何在栈上存储的。
// 它也带了一个指针，指向了vector数据在堆上存储的位置。vector里的字符串对象也就跟着存储在堆上，
// 同样的，这些字符串对象也有自己的专用缓冲区。

// 这就创建了一个树结构，在这个树结构中，每一个值都被唯一的变量拥有。
// 当names离开作用域时，它的值就会被丢弃并最终会引起字符串缓冲区也会被丢弃

// 1. Rust是怎么保证只有一个变量拥有它的值？
// 2. 我们怎么能让多个变量指向相同的数据？
// 3. 我们会被强制要求拷贝所有的东西从而保证某个值被唯一的变量拥有？


// 1. Rust是怎么保证只有一个变量拥有它的值？
// 这是因为Rust在进行类似赋值或者给函数传值的行为时，Rust把值移动给了新的拥有者。

// ```let name = "Pascal".to_string();
// let a = name;
// let b = name;```

// error[E0382]: use of moved value: `name`
//  --> src/main.rs:4:11
//   |
// 2 |   let name = "Pascal".to_string();
//   |       ---- move occurs because `name` has type `std::string::String`, which does not implement the `Copy` trait
// 3 |   let a = name;
//   |           ---- value moved here
// 4 |   let b = name;
//   |           ^^^^ value used here after move

// 我们得到了一个带有很多（有用）信息的编译错误。编译器告诉我们，
// 我们正在尝试在把name移动给a之后接着把它赋值给b。问题在于，当我们尝试把name赋值给b的时候
// ，name实际上已经不再拥有值了。为什么呢？因为在这个时候，所有权已经被移动给a了。

// 让我们看看内存中发生了什么以便于我们更好地理解接下来发生的事情。当name被初始化的时候，它和我们之前的例子很像：


//             +–––+–––+–––+
// stack frame │ • │ 8 │ 6 │ <– name
//             +–│–+–––+–––+
//               │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+

// 但是，当我们把name的值赋值给a的时候，我们也把所有权交给了a，这时候的name是未初始化的。


//             [–– name –– ][––– a –––]
//             +–––+–––+–––+–––+–––+–––+
// stack frame │   │   │   │ • │ 8 │ 6 │ 
//             +–––+–––+–––+–│–+–––+–––+
//                           │
//               +–––––––––––+
//               │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+

// 此时，表达式let b = name会产生一个错误就不足为奇了。这里很重要的一点是
// ，所有的这种静态分析都是由编译器完成，而实际上并没有运行我们的代码。

// 2. 如果我们真的想要有多个变量指向同一块数据呢？
// 有两种方法可以处理，具体采用哪种要看实际情况。对值进行拷贝或者克隆来处理这种情况可能是最简单但是开销最大的方式。
// 显然，这也意味着我们最终还是要复制内存中的数据：


// let name = "Pascal".to_string();
// let a = name;
// let b = a.clone();

// 记住，我们不需要从name克隆值到a因为我们没有试图在name的值赋值给a之后对name进行读取。
// 当我们运行这个程序的时候，数据被丢弃之前，在内存中是像下面这个表示的：

//             [–– name ––] [––– a –––][–––– b ––––]
//             +–––+–––+–––+–––+–––+–––+–––+–––+–––+
// stack frame │   │   │   │ • │ 8 │ 6 │ • │ 8 │ 6 │
//             +–––+–––+–––+–│–+–––+–––+–│–+–––+–––+
//                           │           │
//               +–––––––––––+           +–––––––+
//               │                               │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+–V–+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │   │ P │ a │ s │ c │ a │ l │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+


// 显然，并不是所有的时候都可以对数据进行克隆。根据我们要处理的数据的不同，
// 有时候克隆操作可能是一项对内存开销很高的操作。我们经常需要的可能只是对值的引用。
// 这在我们写一些不需要值的所有权的函数的时候，是非常有用的。假设有一个greet()函数传入name并且只是简单地将其输出:

// fn greet(name: String) {
//     println!("Hello, {}!", name);
// }
// 这个函数并不需要传入值的所有权才能输出。而且，这还会阻止我们对这个传入相同变量的函数进行多次调用：

// let name = "Pascal".to_string();
// greet(name);
// greet(name); // Move happened earlier so this won't compile

// 我们使用&符号对一个变量进行引用。当我们需要一个引用时，我们可以使用这个符号:
// fn greet(name: &String) {
//     println!("Hello, {}!", name);
// }

// 明确地说，我们可能会由于各种原因使用&str取而代之来设计这个API，但是这里不想让它变得太复杂，因为我们现在只需要一个&String。
// let name = "Pascal".to_string();
// greet(&name);
// greet(&name);

// 当一个函数期望传入一个值的引用时，我们说这个函数对这个值进行借用。注意，这里的函数从未得到过传入值的所有权。
// 我们可以用类似的方式解决前面的变量赋值问题：
// let name = "Pascal".to_string();
// let a = &name;
// let b = &name;
// let name = "Pascal".to_string();
// let a = &name;
// let b = a;
// let name = "Pascal".to_string();
// let a = &name;
// greet(a);
// let b = a;
// greet(a);


//             [–s–]
//             +–––+
// stack frame │ • │ 
//             +–│–+
//               │
//             [–│–– s1 –––]
//             +–V–+–––+–––+
//             │ • │ 8 │ 6 │      stack frame
//             +–│–+–––+–––+
//               │\   \   \  
//               │ \   \    length
//               │  \    capacity
//               │    buffer 
//               │          
//             +–V–+–––+–––+–––+–––+–––+–––+–––+
//             │ P │ a │ s │ c │ a │ l │   │   │    heap
//             +–––+–––+–––+–––+–––+–––+–––+–––+



// 什么是引用

// 引用是对内存中的另一个值的非拥有(nonowning)指针类型
// 。引用可以使用借用操作符&来创建，所以下面的代码创建了一个变量x使其拥有值10和一个变量r使其引用x:

// let x = 10;
// let r = &x;

// 因为10是一个原始类型(primitive type)，所以它和引用都存储在栈上。这里是它们在内存中大概的样子

//                    +–––––––+
//                    │       │
//             +–––+––V–+–––+–│–+–––+
// stack frame │   │ 10 │   │ • │   │ 
//             +–––+––––+–––+–––+–––+
//                 [––––]   [–––]
//                   x        r

// 引用可以指向内存中任何地方的值，
// 不仅仅是栈上的。例如下面的代码，创建了一个我们之前在 String vs &str in Rust中讨论过的字符串切片引用(string slice reference)。


// let my_name = "Pascal Precht".to_string();

// let last_name = &my_name[7..];

// String是一个指向存储在堆上的数据的指针类型。字符串切片(string slice)是数据上子串的引用，因此它也是指向堆上的内存。


//                 my_name       last_name
//             [––––––––––––]    [–––––––]
//             +–––+––––+––––+–––+–––+–––+
// stack frame │ • │ 16 │ 13 │   │ • │ 6 │ 
//             +–│–+––––+––––+–––+–│–+–––+
//               │                 │
//               │                 +–––––––––+
//               │                           │
//               │                           │
//               │                         [–│––––––– str –––––––––]
//             +–V–+–––+–––+–––+–––+–––+–––+–V–+–––+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │ P │ r │ e │ c │ h │ t │   │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+


// 关于字符串，我们还可以创建预分配只读内存的字符串字面量(string literals)。
// 例如下面代码中的name就是一个str的引用，str是存放在程序的预分配内存中的。

// let name = "Pascal";

//             name: &str
//             [–––––––]
//             +–––+–––+
// stack frame │ • │ 6 │ 
//             +–│–+–––+
//               │                 
//               +––+                
//                  │
//  preallocated  +–V–+–––+–––+–––+–––+–––+
//  read-only     │ P │ a │ s │ c │ a │ l │
//  memory        +–––+–––+–––+–––+–––+–––+



// 共享引用和可变引用 (Shared and mutable references)


// struct Person {
//     first_name: String,
//     last_name: String,
//     age: u8
//   }
  
//   let p = Person {
//     first_name: "Pascal".to_string(),
//     last_name: "Precht".to_string(),
//     age: 28
//   };
  
//   let r = &p;
  
//   r.age = 29;

// error[E0594]: cannot assign to `r.age` which is behind a `&` reference
//   --> src/main.rs:16:3
//    |
// 14 |   let r = &p;
//    |           -- help: consider changing this to be a mutable reference: `&mut p`
// 15 |   
// 16 |   r.age = 29;
//    |   ^^^^^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written

// Rust关于这个问题的处理十分清晰并且它告诉我们可以使用关键字mut来使&p可变。
// 这对于r和p也是一样的。但是，这样就引入了另外一个特性，即每次只能有一个可变引用。

// let mut r = &mut p;
// let mut r2 = &mut p;

// error[E0499]: cannot borrow `p` as mutable more than once at a time
//   --> src/main.rs:15:16
//    |
// 14 |   let mut r = &mut p;
//    |               ------ first mutable borrow occurs here
// 15 |   let mut r2 = &mut p;
//    |                ^^^^^^ second mutable borrow occurs here
// 16 |   
// 17 |   r.age = 29;
//    |   ---------- first borrow later used here

// Rust声称是内存安全的，而不能对同一份数据进行多个可变引用便是保证内存安全的条件之一。
// 如果在代码的不同地方存在着多个这样的可变引用，就无法保证它们的其中之一不会以不可预期的方式修改数据。

// 另一方面，同一份数据有多个共享引用也是有必要的。所以假定p和r都是不可变的，下面这样做就没有问题:
// let r = &p;
// let r2 = &p;
// let r3 = &p;
// let r4 = &p;
// let r5 = &p;

// 对引用进行引用也是有可能的:
// let r = &p;
// let rr = &r; // &&p
// let rrr = &rr; // &&&p
// let rrrr = &rrr; // &&&&p
// let rrrrr = &rrrrr; // &&&&&p

// 如果我们给一个函数传递一个r5，而实际上是一个&&&&&p，那个函数将会以什么样的方式接收一个引用的引用的引用的引用的...来工作呢？显然，引用可以被解引用。

// 解引用 (Dereferencing References)

// 引用可以使用*操作符来进行解引用从而获取其在内存中指向的值。
// 如果我们使用前面的代码片段，即x拥有值10并且r引用x， 就可以用下面的方式解引用从而进行比较:


// let x = 10;
// let r = &x;

// if *r == 10 {
//   println!("Same!");
// }




// fn main() {
//     let x = 10;
//     let r = &x;
//     let rr = &r; // `rr` is a `&&x`
  
//     if is_ten(rr) {
//       println!("Same!");
//     }
//   }
  
//   fn is_ten(val: &i32) -> bool {
//     *val == 10
//   }



// is_ten()接收一个&i32或者说一个32位有符号整数的引用。
// 尽管实际上我们传递给它的是一个&&i32，或者说是一个32位有符号整数的引用的引用。

// 所以要想让它能够正确运行，似乎val:&i32实际上应该是val:&&i32，表达式*val==10应该是**val==10。
// 事实上，如果把代码按照刚刚那样修改确实可以按照预期结果运行。你可以在这里试试。
// 但是，即使我们没有修改，代码仍然可以正常编译，这里发生了什么？


// Rust的比较操作符(例如==和>=等)是相当智能的，
// 因此只要操作符两边的类型一样，它们可以跟踪一系列的引用直到它们可以找到一个值。
// 这意味着在实际引用中，你可以按照需要进行很多重引用，
// 对于编译器来讲，这些“语法开销(syntactical cost)”是一样的，因为编译器会替你辨别的。


// 隐式解引用和借用(Implicit dereferencing and borrowing)
// 此时，你可能想知道，为什么我在具体的类型上调用方法时不需要使用*操作符？
// 要想说明这个问题，让我们先来看看之前定义的Person结构体:

// struct Person {
//     first_name: String,
//     last_name: String,
//     age: u8
//   }
  
//   fn main() {
//     let pascal = Person {
//       first_name: "Pascal".to_string(),
//       last_name: "Precht".to_string(),
//       age: 28
//     };
  
//     let r = &pascal;
  
//     println!("Hello, {}!", r.first_name);
//   }

// 你应该注意到了，即使我们使用的是一个引用，
// 但是我们没有使用*操作符也能获取引用r里的first_name字段。
// 这里我们看到的是Rust编译期的另一个可用性特性(usability feature )。
// 即.操作符会在需要的时候，进行隐式的解引用。

// 如果没有这个特性的话，可能需要像下面这样写：

// println!("Hello, {}!", (*r).first_name);

// 这也同样适用于借用引用和可变引用。
// 例如，一个数组的sort()方法需要一个&mut self。但是，当我们像下面这样写时也不需要担心:

// let mut numbers = [3, 1, 2];
// numbers.sort();

// .操作符会隐式地对左边的操作符借用一个引用。这意味着，.sort()调用等价于下面的代码：
// (&mut numbers).sort();


// String vs &str

// fn main() {
//     let my_name = "Pascal";
//     greet(my_name);
//   }
  
//   fn greet(name: String) {
//     println!("Hello, {}!", name);
//   }

// error[E0308]: mismatched types
//  --> src/main.rs:3:11
//   |
// 3 |     greet(my_name);
//   |           ^^^^^^^
//   |           |
//   |           expected struct `std::string::String`, found `&str`
//   |           help: try using a conversion method: `my_name.to_string()`

// error: aborting due to previous error

// For more information about this error, try `rustc --explain E0308`.

// Rust编译器很友好地告诉了我们问题所在。
// 很明显，这里我们使用了两个不同的类型: std::string::String，简写为String，和&str。
// 但是greet() 期望传入一个String， 很显然，我们传给函数的类型是&str。 编译器甚至已经提示我们如何修正这个错误。 把第3行改为let my_name= "Pascal".to_string();即可修正这个问题。

//                  buffer
//                    /   capacity
//                  /   /  length
//                /   /   /
//             +–––+–––+–––+
// stack frame │ • │ 8 │ 6 │ <- my_name: String
//             +–│–+–––+–––+
//               │
//             [–│–––––––– capacity –––––––––––]
//               │
//             +–V–+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+

//             [––––––– length ––––––––]
// Rust会在栈上存储String对象。
// 这个对象里包含以下三个信息: 一个指针指向一块分配在堆上的缓冲区，
// 这也是数据真正存储的地方，数据的容量和长度。因此，String对象本身长度总是固定的三个字(word)。

// String之所以为String的一个原因在于它能够根据需要调整缓冲区的容量。例如，我们能够使用push_str()方法追加更多的文本，
// 这种追加操作可能会引起缓冲区的增长。(注意，my_name需要是可变(mutable)的)：
// let mut my_name = "Pascal".to_string();
// my_name.push_str( " Precht");

// 如果你熟悉Rust的Vec<T>类型，你就可以理解String是什么样子的了。因为它们的行为和特性在本质上是相同的，唯一不同地是，String保证内部只保存标准的UTF-8文本。

// 当我们需要引用一个被拥有的UTF-8文本的区间(range)，或者当我们使用字符串字面量(string literals)时，我们就需要使用字符串切片(也就是 str)。

// 如果我们只是对存储在my_name中的last name感兴趣，我们可以像下面这样来获取一个针对字符串中的特定部分的引用:

// let mut my_name = "Pascal".to_string();
// my_name.push_str( " Precht");

// let last_name = &my_name[7..];

//              my_name: String   last_name: &str
//             [––––––––––––]    [–––––––]
//             +–––+––––+––––+–––+–––+–––+
// stack frame │ • │ 16 │ 13 │   │ • │ 6 │ 
//             +–│–+––––+––––+–––+–│–+–––+
//               │                 │
//               │                 +–––––––––+
//               │                           │
//               │                           │
//               │                         [–│––––––– str –––––––––]
//             +–V–+–––+–––+–––+–––+–––+–––+–V–+–––+–––+–––+–––+–––+–––+–––+–––+
//        heap │ P │ a │ s │ c │ a │ l │   │ P │ r │ e │ c │ h │ t │   │   │   │
//             +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+


// 通过指定从第7个字节(因为有空格)开始一直到缓冲区的结尾("..")，last_name现在是一个引用自my_name拥有的文本的字符串切片(string slice)。它借用了这个文本。这里是它在内存中的样子:

// 注意last_name没有在栈上存储容量信息。这是因为它只是对一个字符串切片的引用，而该字符串管理它的容量。这个字符串切片，即str本身，是不确定大小(unsized)的。 而且，在实际使用中，字符串切片总是以引用的形式出现，也就是它们的类型总是&str而不是str。



// 理解字符串字面量(Understanding string literals)
// 正如前面所提到的，有两种情况我们需要使用字符串切片：要么创建一个对子字符串的引用，或者我们使用字符串字面量(string literals)。


// 一个字符串字面量由一串被双引号包含的文本创建，就像我们之前写的:

// let my_name = "Pascal Precht"; // This is a `&str` not a `String`

// 下一个问题是，如果&str是一个引用了被(某人)拥有的String的切片，假定这个文本在适当的地方被创建，那么这么String的所有者是谁？

// 很显然，字符串字面量有点特殊。他们是引用自“预分配文本(preallocated text)”的字符串切片，这个预分配文本存储在可执行程序的只读内存中。换句话说，这是装载我们程序的内存并且不依赖于在堆上分配的缓冲区。

// 也就是说，栈上还有一个入口，指向当程序执行时预分配的内存。

//              my_name: &str
//             [–––––––––––]
//             +–––+–––+
// stack frame │ • │ 6 │ 
//             +–│–+–––+
//               │                 
//               +––+                
//                  │
//  preallocated  +–V–+–––+–––+–––+–––+–––+
//  read-only     │ P │ a │ s │ c │ a │ l │
//  memory        +–––+–––+–––+–––+–––+–––+

// 显然，这取决于很多因素，
// 但是一般地，保守来讲，如果我们正在构建的API不需要拥有或者修改使用的文本，那么应该使用&str而不是String。
// // 这意味着，我们可以改进一下最原始的greet()函数:

// fn greet(name: &str) {
//     println!("Hello, {}!", name);
//   }

// 等一下，但是如果这个API的调用者真的有一个String并且出于某些未知原因无法将其转换成&str呢？
// 完全没有问题。Rust有一个超级强大的特性叫做deref coercing，这个特性能够允许把传进来的带有借用操作符的String引用，
// 也就是&String，在API执行之前转成&str。我们会在另一篇文章里介绍更多地相关细节。

// fn main() {
//     let first_name = "Pascal";
//     let last_name = "Precht".to_string();
  
//     greet(first_name);
//     greet(&last_name); // `last_name` is passed by reference
//   }
  
//   fn greet(name: &str) {
//     println!("Hello, {}!", name);
//   }



















































